package com.chiancloud.shield.common.params;

import com.beust.jcommander.Parameter;
import com.beust.jcommander.ParametersDelegate;
import com.chiancloud.shield.core.conf.ConfTree;
import com.chiancloud.shield.core.conf.ConfTreeOperations;
import com.chiancloud.shield.core.exception.BadCommandArgumentsException;
import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.fs.Path;

import java.io.File;
import java.util.List;
import java.util.Map;


public abstract class AbstractClusterBuildingActionArgs extends
    AbstractActionArgs {

  @Parameter(names = ARG_CONFDIR,
      description = "Path to cluster configuration directory in HDFS",
      converter = PathArgumentConverter.class)
  public Path confdir;

  @Parameter(names = ARG_ZKPATH,
      description = "Zookeeper path for the application")
  public String appZKPath;

  @Parameter(names = ARG_ZKHOSTS,
      description = "comma separated list of the Zookeeper hosts")
  public String zkhosts;

  @Parameter(names = ARG_IMAGE,
      description = "The full path to a .tar or .tar.gz path containing the application",
      converter = PathArgumentConverter.class)
  public Path image;

  @Parameter(names = ARG_APP_HOME,
      description = "Home directory of a pre-installed application")
  public String appHomeDir;

  @Parameter(names = ARG_PROVIDER,
      description = "Provider of the specific cluster application")
  public String provider = ShieldProviderFactory.DEFAULT_CLUSTER_TYPE;

  @Parameter(names = {ARG_PACKAGE},
      description = "URI to a slider package")
  public String packageURI;

  @Parameter(names = {ARG_RESOURCES},
      description = "File defining the resources of this instance")
  public File resources;

  @Parameter(names = {ARG_TEMPLATE},
      description = "Template application configuration")
  public File template;

  @ParametersDelegate
  public ComponentArgsDelegate componentDelegate = new ComponentArgsDelegate();


  @ParametersDelegate
  public AppAndResouceOptionArgsDelegate optionsDelegate =
      new AppAndResouceOptionArgsDelegate();


  public Map<String, String> getOptionsMap() throws
      BadCommandArgumentsException {
    return optionsDelegate.getOptionsMap();
  }


  public Map<String, Map<String, String>> getCompOptionMap() throws
          BadCommandArgumentsException {
    return optionsDelegate.getCompOptionMap();
  }


  public Map<String, String> getResourceOptionsMap() throws
      BadCommandArgumentsException {
    return optionsDelegate.getResourceOptionsMap();
  }

  public Map<String, Map<String, String>> getResourceCompOptionMap() throws
      BadCommandArgumentsException {
    return optionsDelegate.getResourceCompOptionMap();
  }

  @VisibleForTesting
  public List<String> getComponentTuples() {
    return componentDelegate.getComponentTuples();
  }


  public Map<String, String> getComponentMap() throws
      BadCommandArgumentsException {
    return componentDelegate.getComponentMap();
  }

  public Path getConfdir() {
    return confdir;
  }

  public String getAppZKPath() {
    return appZKPath;
  }

  public String getZKhosts() {
    return zkhosts;
  }

  public Path getImage() {
    return image;
  }

  public String getAppHomeDir() {
    return appHomeDir;
  }

  public String getProvider() {
    return provider;
  }

  public ConfTree buildAppOptionsConfTree() throws
      BadCommandArgumentsException {
    return buildConfTree(getOptionsMap());
  }

  public ConfTree buildResourceOptionsConfTree() throws
      BadCommandArgumentsException {
    return buildConfTree(getResourceOptionsMap());
  }

  protected ConfTree buildConfTree(Map<String, String> optionsMap) throws
      BadCommandArgumentsException {
    ConfTree confTree = new ConfTree();
    ConfTreeOperations ops = new ConfTreeOperations(confTree);
    confTree.global.putAll(optionsMap);
    Map<String, Map<String, String>> roleOptionMap = getCompOptionMap();
    for (Map.Entry<String, Map<String, String>> entry : roleOptionMap.entrySet()) {
      String key = entry.getKey();
      Map<String, String> value = entry.getValue();
      ops.getOrAddComponent(key).putAll(value);
    }
    return confTree;
  }
}
